/*
 *  UVCCamera
 *  library and sample to access to UVC web camera on non-rooted Android device
 *
 * Copyright (c) 2014-2017 saki t_saki@serenegiant.com
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 *
 *  All files in the folder are under this Apache License, Version 2.0.
 *  Files in the libjpeg-turbo, libusb, libuvc, rapidjson folder
 *  may have a different license, see the respective files.
 */

package com.serenegiant.usb;

import java.io.UnsupportedEncodingException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbDeviceConnection;
import android.hardware.usb.UsbInterface;
import android.hardware.usb.UsbManager;
import android.os.Handler;
import android.text.TextUtils;
import android.util.Log;
import android.util.SparseArray;

import com.serenegiant.utils.BuildCheck;
import com.serenegiant.utils.HandlerThreadHandler;

public final class USBMonitor {
    /**
     * 开关调试模式，即是否打印相应相关log
     */
    private static final boolean DEBUG = false;    // TODO set false on production
    private static final String TAG = "USBMonitor";

    private static final String ACTION_USB_PERMISSION_BASE = "com.serenegiant.USB_PERMISSION.";

    // usb 权限字符串+USBMonitor类的hashCode值
    private final String ACTION_USB_PERMISSION = ACTION_USB_PERMISSION_BASE + hashCode();

    // usb 接入设备
    public static final String ACTION_USB_DEVICE_ATTACHED = "android.hardware.usb.action.USB_DEVICE_ATTACHED";

    /**
     * openしているUsbControlBlock
     */
    private final ConcurrentHashMap<UsbDevice, UsbControlBlock> mCtrlBlocks = new ConcurrentHashMap<UsbDevice, UsbControlBlock>();
    private final SparseArray<WeakReference<UsbDevice>> mHasPermissions = new SparseArray<WeakReference<UsbDevice>>();

    private final WeakReference<Context> mWeakContext;

    /**
     * 获得Usb的状态，与连接的Usb设备通信，usb 是系统服务，通过 getSystemService 获取
     */
    private final UsbManager mUsbManager;

    private final OnDeviceConnectListener mOnDeviceConnectListener;
    private PendingIntent mPermissionIntent = null;
    private List<DeviceFilter> mDeviceFilters = new ArrayList<DeviceFilter>();

    /**
     * コールバックをワーカースレッドで呼び出すためのハンドラー
     */
    private final Handler mAsyncHandler;

    // 标记该变量是原子操作，保证操作准确和一致性
    private volatile boolean destroyed;

    /**
     * 说明：连接监听接口
     * 调用设备连接监听器的断开连接，连接监听器是暴露在外的接口，供用户操做，内部操做全部有 mConnection 完成
     */
    public interface OnDeviceConnectListener {
        /**
         * called when device attached
         *
         * @param device
         */
        public void onAttach(UsbDevice device);

        /**
         * called when device dettach(after onDisconnect)
         *
         * @param device
         */
        public void onDettach(UsbDevice device);

        /**
         * called after device opend
         *
         * @param device
         * @param ctrlBlock
         * @param createNew
         */
        public void onConnect(UsbDevice device, UsbControlBlock ctrlBlock, boolean createNew);

        /**
         * called when USB device removed or its power off (this callback is called after device closing)
         *
         * @param device
         * @param ctrlBlock
         */
        public void onDisconnect(UsbDevice device, UsbControlBlock ctrlBlock);

        /**
         * called when canceled or could not get permission from user
         *
         * @param device
         */
        public void onCancel(UsbDevice device);
    }

    public USBMonitor(final Context context, final OnDeviceConnectListener listener) {
        if (DEBUG) {
            Log.v(TAG, "USBMonitor:Constructor");
        }
        if (listener == null) {
            throw new IllegalArgumentException("OnDeviceConnectListener should not null.");
        }

        mWeakContext = new WeakReference<Context>(context);

        mUsbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);

        mOnDeviceConnectListener = listener;

        mAsyncHandler = HandlerThreadHandler.createHandler(TAG);

        destroyed = false;

        if (DEBUG){
            Log.v(TAG, "USBMonitor:mUsbManager=" + mUsbManager);
        }
    }

    /**
     * 不在使用时，释放所有连接的资源
     */
    public void destroy() {
        if (DEBUG) {
            Log.i(TAG, "destroy:");
        }
        // 主要广播
        unregister();
        // 标记设备已被销毁
        if (!destroyed) {
            destroyed = true;
            // 清楚控制模块列表，并清楚每一个控制模块对应的资源（UsbInterface）
            final Set<UsbDevice> keys = mCtrlBlocks.keySet();
            if (keys != null) {
                UsbControlBlock ctrlBlock;
                try {
                    for (final UsbDevice key : keys) {
                        ctrlBlock = mCtrlBlocks.remove(key);
                        if (ctrlBlock != null) {
                            ctrlBlock.close();
                        }
                    }
                } catch (final Exception e) {
                    Log.e(TAG, "destroy:", e);
                }
            }
            mCtrlBlocks.clear();
            try {
                // handler 释放 looper
                mAsyncHandler.getLooper().quit();
            } catch (final Exception e) {
                Log.e(TAG, "destroy:", e);
            }
        }
    }

    /**
     * 注册广播为了监听 USB 事件
     *
     * @throws IllegalStateException
     */
    public synchronized void register() throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        if (mPermissionIntent == null) {
            if (DEBUG) {
                Log.i(TAG, "register:");
            }
            final Context context = mWeakContext.get();
            if (context != null) {
                // 创建一个广播的 PendingIntent
                mPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
                final IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
                // ACTION_USB_DEVICE_ATTACHED never comes on some devices so it should not be added here
                filter.addAction(UsbManager.ACTION_USB_DEVICE_DETACHED);
                context.registerReceiver(mUsbReceiver, filter);
            }
            // start connection check
            mDeviceCounts = 0;
            mAsyncHandler.postDelayed(mDeviceCheckRunnable, 1000);
        }
    }

    /**
     * 注销广播
     *
     * @throws IllegalStateException
     */
    public synchronized void unregister() throws IllegalStateException {
        // 接続チェック用Runnableを削除
        mDeviceCounts = 0;
        if (!destroyed) {
            mAsyncHandler.removeCallbacks(mDeviceCheckRunnable);
        }
        if (mPermissionIntent != null) {
//			if (DEBUG) Log.i(TAG, "unregister:");
            final Context context = mWeakContext.get();
            try {
                if (context != null) {
                    context.unregisterReceiver(mUsbReceiver);
                }
            } catch (final Exception e) {
                Log.w(TAG, e);
            }
            mPermissionIntent = null;
        }
    }

    /**
     * 判断设备是否登记注册
     *
     * @return
     */
    public synchronized boolean isRegistered() {
        return !destroyed && (mPermissionIntent != null);
    }

    /**
     * 往设备过滤器列表中，加入一个过滤器，会先重置过滤器列表，在添加一个新的
     *
     * @param filter
     * @throws IllegalStateException
     */
    public void setDeviceFilter(final DeviceFilter filter) throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        mDeviceFilters.clear();
        mDeviceFilters.add(filter);
    }

    /**
     * 添加指定的过滤器
     *
     * @param filter
     * @throws IllegalStateException
     */
    public void addDeviceFilter(final DeviceFilter filter) throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        mDeviceFilters.add(filter);
    }

    /**
     * 移除指定的过滤器
     *
     * @param filter
     * @throws IllegalStateException
     */
    public void removeDeviceFilter(final DeviceFilter filter) throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        mDeviceFilters.remove(filter);
    }

    /**
     * 重置 device filters
     *
     * @param filters
     * @throws IllegalStateException
     */
    public void setDeviceFilter(final List<DeviceFilter> filters) throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        mDeviceFilters.clear();
        mDeviceFilters.addAll(filters);
    }

    /**
     * 添加设备过滤器
     *
     * @param filters
     * @throws IllegalStateException
     */
    public void addDeviceFilter(final List<DeviceFilter> filters) throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        mDeviceFilters.addAll(filters);
    }

    /**
     * 移除 device filters
     *
     * @param filters
     */
    public void removeDeviceFilter(final List<DeviceFilter> filters) throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        mDeviceFilters.removeAll(filters);
    }

    /**
     * 获取通过匹配的 USB 设备数
     *
     * @return
     * @throws IllegalStateException
     */
    public int getDeviceCount() throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        return getDeviceList().size();
    }

    /**
     * 返回插入主机的USB设备列表，若无，则为 null
     * 通过 mUsbManager.getDeviceList(); 获取列表
     *
     * @return
     * @throws IllegalStateException
     */
    public List<UsbDevice> getDeviceList() throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        return getDeviceList(mDeviceFilters);
    }

    /**
     * 返回插入主机的USB设备列表，若无，则为 null
     * 通过 mUsbManager.getDeviceList(); 获取列表
     *
     * @param filters
     * @return
     * @throws IllegalStateException
     */
    public List<UsbDevice> getDeviceList(final List<DeviceFilter> filters) throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        final HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
        final List<UsbDevice> result = new ArrayList<UsbDevice>();
        if (deviceList != null) {
            if ((filters == null) || filters.isEmpty()) {
                result.addAll(deviceList.values());
            } else {
                for (final UsbDevice device : deviceList.values()) {
                    for (final DeviceFilter filter : filters) {
                        // 用传入的 DeviceFilter 去匹配设备，如果匹配上，就加入设备列表
                        if ((filter != null) && filter.matches(device)) {
                            // 当 过滤器 匹配通过，判断USB设备是否遭排斥，如果没有，则加入设备列表
                            if (!filter.isExclude) {
                                result.add(device);
                            }
                            break;
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * 返回设备列表，如果没有匹配的设备，返回的集合为空
     *
     * @param filter
     * @return
     * @throws IllegalStateException
     */
    public List<UsbDevice> getDeviceList(final DeviceFilter filter) throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        // USB 系统 API
        final HashMap<String, UsbDevice> deviceList = mUsbManager.getDeviceList();
        final List<UsbDevice> result = new ArrayList<UsbDevice>();
        if (deviceList != null) {
            // 遍历 HashMap ,设备列表
            for (final UsbDevice device : deviceList.values()) {
                if ((filter == null) || (filter.matches(device) && !filter.isExclude)) {
                    result.add(device);
                }
            }
        }
        return result;
    }

    /**
     * 获取 USB 设备列表的迭代器，没有过滤器
     *
     * @return
     * @throws IllegalStateException
     */
    public Iterator<UsbDevice> getDevices() throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        Iterator<UsbDevice> iterator = null;
        final HashMap<String, UsbDevice> list = mUsbManager.getDeviceList();
        if (list != null) {
            iterator = list.values().iterator();
        }
        return iterator;
    }

    /**
     * 打印设备列表到控制台
     */
    public final void dumpDevices() {
        final HashMap<String, UsbDevice> list = mUsbManager.getDeviceList();
        if (list != null) {
            final Set<String> keys = list.keySet();
            if (keys != null && keys.size() > 0) {
                final StringBuilder sb = new StringBuilder();
                for (final String key : keys) {
                    final UsbDevice device = list.get(key);
                    final int num_interface = device != null ? device.getInterfaceCount() : 0;
                    sb.setLength(0);
                    for (int i = 0; i < num_interface; i++) {
                        sb.append(String.format(Locale.US, "interface%d:%s", i, device.getInterface(i).toString()));
                    }
                    Log.i(TAG, "key=" + key + ":" + device + ":" + sb.toString());
                }
            } else {
                Log.i(TAG, "no device");
            }
        } else {
            Log.i(TAG, "no device");
        }
    }

    /**
     * 返回特定的 USB 是否有对应的权限
     *
     * @param device
     * @return true: 指定したUsbDeviceにパーミッションがある
     * @throws IllegalStateException
     */
    public final boolean hasPermission(final UsbDevice device) throws IllegalStateException {
        if (destroyed) {
            throw new IllegalStateException("already destroyed");
        }
        return updatePermission(device, device != null && mUsbManager.hasPermission(device));
    }

    /**
     * 确定是否有访问某USB设备的权限，
     * 有，但相应设备的引用为空，则新建对象，并加入权限列表
     * 没有，就从权限集合中移除，
     *
     * @param device
     * @param hasPermission
     * @return hasPermission
     */
    private boolean updatePermission(final UsbDevice device, final boolean hasPermission) {
        // 获取设备对应的 HashCode
        final int deviceKey = getDeviceKey(device, true);
        synchronized (mHasPermissions) {
            if (hasPermission) {
                if (mHasPermissions.get(deviceKey) == null) {
                    mHasPermissions.put(deviceKey, new WeakReference<UsbDevice>(device));
                }
            } else {
                mHasPermissions.remove(deviceKey);
            }
        }
        return hasPermission;
    }

    /**
     * 请求访问 USB 设备的权限
     *
     * @param device
     * @return 权限获取失败，返回true
     */
    public synchronized boolean requestPermission(final UsbDevice device) {
        if (DEBUG) {
            Log.v(TAG, "requestPermission:device=" + device);
        }
        boolean result = false;
        if (isRegistered()) {
            if (device != null) {
                // 在 open 前判断是否有连接权限；对于连接权限可以静态分配，也可以动态分配权限
                if (mUsbManager.hasPermission(device)) {
                    // 如果 app 已经具有相应的权限，就调用连接监听的 onConnect 方法
                    processConnect(device);
                } else {
                    try {
                        // 弹出权限对话框，向用户获取相应的权限
                        mUsbManager.requestPermission(device, mPermissionIntent);
                    } catch (final Exception e) {
                        // Android5.1.x 的 GALAXY系列 android.permission.sec.MDM_APP_MGMT という意味不明の例外生成するみたい
                        // 权限获取失败，就取消连接
                        Log.w(TAG, e);
                        processCancel(device);
                        result = true;
                    }
                }
            } else {
                processCancel(device);
                result = true;
            }
        } else {
            processCancel(device);
            result = true;
        }
        return result;
    }

    /**
     * 给指定的 USB 设备绑定控制模块
     *
     * @param device
     * @return
     * @throws SecurityException
     */
    public UsbControlBlock openDevice(final UsbDevice device) throws SecurityException {
        if (hasPermission(device)) {
            UsbControlBlock result = mCtrlBlocks.get(device);
            if (result == null) {
                result = new UsbControlBlock(USBMonitor.this, device);
                mCtrlBlocks.put(device, result);
            }
            return result;
        } else {
            throw new SecurityException("has no permission");
        }
    }

    /**
     * 该广播接收者用户 USB 权限
     */
    private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {

        @Override
        public void onReceive(final Context context, final Intent intent) {
            if (destroyed) return;
            final String action = intent.getAction();
            if (ACTION_USB_PERMISSION.equals(action)) {
                // when received the result of requesting USB permission
                synchronized (USBMonitor.this) {
                    final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                    if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
                        if (device != null) {
                            // get permission, call onConnect
                            processConnect(device);
                        }
                    } else {
                        // failed to get permission
                        processCancel(device);
                    }
                }
            } else if (UsbManager.ACTION_USB_DEVICE_ATTACHED.equals(action)) {
                final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                updatePermission(device, hasPermission(device));
                processAttach(device);
            } else if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) {
                // when device removed
                final UsbDevice device = intent.getParcelableExtra(UsbManager.EXTRA_DEVICE);
                if (device != null) {
                    UsbControlBlock ctrlBlock = mCtrlBlocks.remove(device);
                    if (ctrlBlock != null) {
                        // cleanup
                        ctrlBlock.close();
                    }
                    mDeviceCounts = 0;
                    processDettach(device);
                }
            }
        }
    };

    /**
     * 检测到的连接设备数量
     */
    private volatile int mDeviceCounts = 0;


    /**
     * 周期性的检查设备的连接状况，并检查对应的权限
     */
    private final Runnable mDeviceCheckRunnable = new Runnable() {
        @Override
        public void run() {
            if (destroyed) {
                return;
            }
            final List<UsbDevice> devices = getDeviceList();
            final int n = devices.size();
            final int hasPermissionCounts;
            final int m;
            synchronized (mHasPermissions) {
                hasPermissionCounts = mHasPermissions.size();
                mHasPermissions.clear();
                for (final UsbDevice device : devices) {
                    hasPermission(device);
                }
                m = mHasPermissions.size();
            }
            if ((n > mDeviceCounts) || (m > hasPermissionCounts)) {
                mDeviceCounts = n;
                if (mOnDeviceConnectListener != null) {
                    for (int i = 0; i < n; i++) {
                        final UsbDevice device = devices.get(i);
                        mAsyncHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                mOnDeviceConnectListener.onAttach(device);
                            }
                        });
                    }
                }
            }
            mAsyncHandler.postDelayed(this, 2000);    // 每 2S 确定一次
        }
    };

    /**
     * 打开选中的 USB 设备
     *
     * @param device
     */
    private final void processConnect(final UsbDevice device) {
        if (destroyed) {
            return;
        }
        // 更新权限，将设备访问权限，加入权限列表
        updatePermission(device, true);
        mAsyncHandler.post(new Runnable() {
            @Override
            public void run() {
                if (DEBUG) {
                    Log.v(TAG, "processConnect:device=" + device);
                }
                UsbControlBlock ctrlBlock;
                // 用于标记是否新建了一个关联设备的控制模块，该变量，暂未使用
                final boolean createNew;
                // mCtrlBlocks ConcurrentHashMap,存储设备、设备控制模块
                ctrlBlock = mCtrlBlocks.get(device);
                if (ctrlBlock == null) {
                    ctrlBlock = new UsbControlBlock(USBMonitor.this, device);
                    // 若设备没有关联控制模块，新建设备关联的控制模块，并加入 ConcurrentHashMap
                    mCtrlBlocks.put(device, ctrlBlock);
                    createNew = true;
                } else {
                    createNew = false;
                }
                if (mOnDeviceConnectListener != null) {
                    mOnDeviceConnectListener.onConnect(device, ctrlBlock, createNew);
                }
            }
        });
    }

    /**
     * 取消，功能待定
     *
     * @param device
     */
    private final void processCancel(final UsbDevice device) {
        if (destroyed) {
            return;
        }
        if (DEBUG) {
            Log.v(TAG, "processCancel:");
        }
        // 从权限列表中，移除该设备的权限
        updatePermission(device, false);
        if (mOnDeviceConnectListener != null) {
            mAsyncHandler.post(new Runnable() {
                @Override
                public void run() {
                    mOnDeviceConnectListener.onCancel(device);
                }
            });
        }
    }

    /**
     * usb 插入设备，回调连接监听器的 onAttach
     *
     * @param device
     */
    private final void processAttach(final UsbDevice device) {
        if (destroyed) {
            return;
        }
        if (DEBUG) {
            Log.v(TAG, "processAttach:");
        }
        if (mOnDeviceConnectListener != null) {
            mAsyncHandler.post(new Runnable() {
                @Override
                public void run() {
                    mOnDeviceConnectListener.onAttach(device);
                }
            });
        }
    }

    /**
     * usb 拔出主板，回调连接监听器的 onDettach
     *
     * @param device
     */
    private final void processDettach(final UsbDevice device) {
        if (destroyed) {
            return;
        }
        if (DEBUG) {
            Log.v(TAG, "processDettach:");
        }
        if (mOnDeviceConnectListener != null) {
            mAsyncHandler.post(new Runnable() {
                @Override
                public void run() {
                    mOnDeviceConnectListener.onDettach(device);
                }
            });
        }
    }

    /**
     * 获取设备的各项信息
     *
     * @param device nullなら空文字列を返す
     * @return
     */
    public static final String getDeviceKeyName(final UsbDevice device) {
        return getDeviceKeyName(device, null, false);
    }

    /**
     * 获取设备的各项信息
     *
     * @param device
     * @param useNewAPI
     * @return
     */
    public static final String getDeviceKeyName(final UsbDevice device, final boolean useNewAPI) {
        return getDeviceKeyName(device, null, useNewAPI);
    }

    /**
     * 获取设备的各项信息
     *
     * @param device    nullなら空文字列を返す
     * @param serial    UsbDeviceConnection#getSerialで取得したシリアル番号を渡す, nullでuseNewAPI=trueでAPI>=21なら内部で取得
     * @param useNewAPI API>=21またはAPI>=23のみで使用可能なメソッドも使用する(ただし機器によってはnullが返ってくるので有効かどうかは機器による)
     * @return
     */
    @SuppressLint("NewApi")
    public static final String getDeviceKeyName(final UsbDevice device, final String serial, final boolean useNewAPI) {
        if (device == null) {
            return "";
        }
        final StringBuilder sb = new StringBuilder();

        sb.append(device.getVendorId());
        sb.append("#");    // API >= 12
        sb.append(device.getProductId());
        sb.append("#");    // API >= 12
        sb.append(device.getDeviceClass());
        sb.append("#");    // API >= 12
        sb.append(device.getDeviceSubclass());
        sb.append("#");    // API >= 12
        sb.append(device.getDeviceProtocol());   // API >= 12

        if (!TextUtils.isEmpty(serial)) {
            sb.append("#");
            sb.append(serial);
        }
        if (useNewAPI && BuildCheck.isAndroid5()) {
            sb.append("#");
            if (TextUtils.isEmpty(serial)) {
                sb.append(device.getSerialNumber());
                sb.append("#");    // API >= 21
            }
            sb.append(device.getManufacturerName());
            sb.append("#");    // API >= 21
            sb.append(device.getConfigurationCount());
            sb.append("#");    // API >= 21
            if (BuildCheck.isMarshmallow()) {
                sb.append(device.getVersion());
                sb.append("#");    // API >= 23
            }
        }
//		if (DEBUG) Log.v(TAG, "getDeviceKeyName:" + sb.toString());
        return sb.toString();
    }

    /**
     * 以下三个方法，获取 USB 设备描述字符串对应的 HashCode，为重载方法
     * <p>
     * デバイスキーを整数として取得
     * getDeviceKeyNameで得られる文字列のhasCodeを取得
     * ベンダーID, プロダクトID, デバイスクラス, デバイスサブクラス, デバイスプロトコルから生成
     * 同種の製品だと同じデバイスキーになるので注意
     *
     * @param device nullなら0を返す
     * @return
     */
    public static final int getDeviceKey(final UsbDevice device) {
        return device != null ? getDeviceKeyName(device, null, false).hashCode() : 0;
    }

    /**
     * 获取 USB 设备描述字符串对应的 HashCode
     *
     * @param device
     * @param useNewAPI
     * @return
     */
    public static final int getDeviceKey(final UsbDevice device, final boolean useNewAPI) {
        return device != null ? getDeviceKeyName(device, null, useNewAPI).hashCode() : 0;
    }

    /**
     * デバイスキーを整数として取得
     * getDeviceKeyNameで得られる文字列のhasCodeを取得
     * serialがnullでuseNewAPI=falseで同種の製品だと同じデバイスキーになるので注意
     *
     * @param device    nullなら0を返す
     * @param serial    UsbDeviceConnection#getSerialで取得したシリアル番号を渡す, nullでuseNewAPI=trueでAPI>=21なら内部で取得
     * @param useNewAPI API>=21またはAPI>=23のみで使用可能なメソッドも使用する(ただし機器によってはnullが返ってくるので有効かどうかは機器による)
     * @return
     */
    public static final int getDeviceKey(final UsbDevice device, final String serial, final boolean useNewAPI) {
        return device != null ? getDeviceKeyName(device, serial, useNewAPI).hashCode() : 0;
    }

    /**
     * 用于承载 usb 设备信息
     */
    public static class UsbDeviceInfo {
        // usb版本
        public String usb_version;
        // 制造商
        public String manufacturer;
        public String product;
        public String version;
        public String serial;

        private void clear() {
            usb_version = manufacturer = product = version = serial = null;
        }

        @Override
        public String toString() {
            return String.format("UsbDevice:usb_version=%s,manufacturer=%s,product=%s,version=%s,serial=%s",
                    usb_version != null ? usb_version : "",
                    manufacturer != null ? manufacturer : "",
                    product != null ? product : "",
                    version != null ? version : "",
                    serial != null ? serial : "");
        }
    }

    private static final int USB_DIR_OUT = 0;
    private static final int USB_DIR_IN = 0x80;
    private static final int USB_TYPE_MASK = (0x03 << 5);
    private static final int USB_TYPE_STANDARD = (0x00 << 5);
    private static final int USB_TYPE_CLASS = (0x01 << 5);
    private static final int USB_TYPE_VENDOR = (0x02 << 5);
    private static final int USB_TYPE_RESERVED = (0x03 << 5);
    private static final int USB_RECIP_MASK = 0x1f;
    private static final int USB_RECIP_DEVICE = 0x00;
    private static final int USB_RECIP_INTERFACE = 0x01;
    private static final int USB_RECIP_ENDPOINT = 0x02;
    private static final int USB_RECIP_OTHER = 0x03;
    private static final int USB_RECIP_PORT = 0x04;
    private static final int USB_RECIP_RPIPE = 0x05;
    private static final int USB_REQ_GET_STATUS = 0x00;
    private static final int USB_REQ_CLEAR_FEATURE = 0x01;
    private static final int USB_REQ_SET_FEATURE = 0x03;
    private static final int USB_REQ_SET_ADDRESS = 0x05;
    private static final int USB_REQ_GET_DESCRIPTOR = 0x06;
    private static final int USB_REQ_SET_DESCRIPTOR = 0x07;
    private static final int USB_REQ_GET_CONFIGURATION = 0x08;
    private static final int USB_REQ_SET_CONFIGURATION = 0x09;
    private static final int USB_REQ_GET_INTERFACE = 0x0A;
    private static final int USB_REQ_SET_INTERFACE = 0x0B;
    private static final int USB_REQ_SYNCH_FRAME = 0x0C;
    private static final int USB_REQ_SET_SEL = 0x30;
    private static final int USB_REQ_SET_ISOCH_DELAY = 0x31;
    private static final int USB_REQ_SET_ENCRYPTION = 0x0D;
    private static final int USB_REQ_GET_ENCRYPTION = 0x0E;
    private static final int USB_REQ_RPIPE_ABORT = 0x0E;
    private static final int USB_REQ_SET_HANDSHAKE = 0x0F;
    private static final int USB_REQ_RPIPE_RESET = 0x0F;
    private static final int USB_REQ_GET_HANDSHAKE = 0x10;
    private static final int USB_REQ_SET_CONNECTION = 0x11;
    private static final int USB_REQ_SET_SECURITY_DATA = 0x12;
    private static final int USB_REQ_GET_SECURITY_DATA = 0x13;
    private static final int USB_REQ_SET_WUSB_DATA = 0x14;
    private static final int USB_REQ_LOOPBACK_DATA_WRITE = 0x15;
    private static final int USB_REQ_LOOPBACK_DATA_READ = 0x16;
    private static final int USB_REQ_SET_INTERFACE_DS = 0x17;

    private static final int USB_REQ_STANDARD_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_DEVICE);        // 0x10
    private static final int USB_REQ_STANDARD_DEVICE_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE);            // 0x90
    private static final int USB_REQ_STANDARD_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_INTERFACE);    // 0x11
    private static final int USB_REQ_STANDARD_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_INTERFACE);    // 0x91
    private static final int USB_REQ_STANDARD_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT);    // 0x12
    private static final int USB_REQ_STANDARD_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_ENDPOINT);        // 0x92

    private static final int USB_REQ_CS_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE);                // 0x20
    private static final int USB_REQ_CS_DEVICE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE);                    // 0xa0
    private static final int USB_REQ_CS_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE);            // 0x21
    private static final int USB_REQ_CS_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);            // 0xa1
    private static final int USB_REQ_CS_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT);                // 0x22
    private static final int USB_REQ_CS_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT);                // 0xa2

    private static final int USB_REQ_VENDER_DEVICE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_DEVICE);                // 0x40
    private static final int USB_REQ_VENDER_DEVICE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE);                // 0xc0
    private static final int USB_REQ_VENDER_INTERFACE_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE);        // 0x41
    private static final int USB_REQ_VENDER_INTERFACE_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE);        // 0xc1
    private static final int USB_REQ_VENDER_ENDPOINT_SET = (USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_ENDPOINT);            // 0x42
    private static final int USB_REQ_VENDER_ENDPOINT_GET = (USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_ENDPOINT);            // 0xc2

    private static final int USB_DT_DEVICE = 0x01;
    private static final int USB_DT_CONFIG = 0x02;
    private static final int USB_DT_STRING = 0x03;
    private static final int USB_DT_INTERFACE = 0x04;
    private static final int USB_DT_ENDPOINT = 0x05;
    private static final int USB_DT_DEVICE_QUALIFIER = 0x06;
    private static final int USB_DT_OTHER_SPEED_CONFIG = 0x07;
    private static final int USB_DT_INTERFACE_POWER = 0x08;
    private static final int USB_DT_OTG = 0x09;
    private static final int USB_DT_DEBUG = 0x0a;
    private static final int USB_DT_INTERFACE_ASSOCIATION = 0x0b;
    private static final int USB_DT_SECURITY = 0x0c;
    private static final int USB_DT_KEY = 0x0d;
    private static final int USB_DT_ENCRYPTION_TYPE = 0x0e;
    private static final int USB_DT_BOS = 0x0f;
    private static final int USB_DT_DEVICE_CAPABILITY = 0x10;
    private static final int USB_DT_WIRELESS_ENDPOINT_COMP = 0x11;
    private static final int USB_DT_WIRE_ADAPTER = 0x21;
    private static final int USB_DT_RPIPE = 0x22;
    private static final int USB_DT_CS_RADIO_CONTROL = 0x23;
    private static final int USB_DT_PIPE_USAGE = 0x24;
    private static final int USB_DT_SS_ENDPOINT_COMP = 0x30;
    private static final int USB_DT_CS_DEVICE = (USB_TYPE_CLASS | USB_DT_DEVICE);
    private static final int USB_DT_CS_CONFIG = (USB_TYPE_CLASS | USB_DT_CONFIG);
    private static final int USB_DT_CS_STRING = (USB_TYPE_CLASS | USB_DT_STRING);
    private static final int USB_DT_CS_INTERFACE = (USB_TYPE_CLASS | USB_DT_INTERFACE);
    private static final int USB_DT_CS_ENDPOINT = (USB_TYPE_CLASS | USB_DT_ENDPOINT);
    private static final int USB_DT_DEVICE_SIZE = 18;

    /**
     * 获取USB设备指定 ID 的描述信息
     *
     * @param connection
     * @param id
     * @param languageCount
     * @param languages
     * @return
     */
    private static String getString(final UsbDeviceConnection connection, final int id, final int languageCount, final byte[] languages) {
        final byte[] work = new byte[256];
        String result = null;
        for (int i = 1; i <= languageCount; i++) {

            int ret = connection.controlTransfer(
                    USB_REQ_STANDARD_DEVICE_GET, // USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE
                    USB_REQ_GET_DESCRIPTOR,
                    (USB_DT_STRING << 8) | id, languages[i], work, 256, 0);

            if ((ret > 2) && (work[0] == ret) && (work[1] == USB_DT_STRING)) {
                // skip first two bytes(bLength & bDescriptorType), and copy the rest to the string
                try {
                    result = new String(work, 2, ret - 2, "UTF-16LE");
                    if (!"Љ".equals(result)) {    // 変なゴミが返ってくる時がある
                        break;
                    } else {
                        result = null;
                    }
                } catch (final UnsupportedEncodingException e) {
                    // ignore
                }
            }
        }
        return result;
    }

    /**
     * 获取 USB 设备的相关信息
     *
     * @param device
     * @return
     */
    public UsbDeviceInfo getDeviceInfo(final UsbDevice device) {
        return updateDeviceInfo(mUsbManager, device, null);
    }

    /**
     * 获取 USB 设备的相关信息，内部调用 updateDeviceInfo 去获取具体 USB 设备的信息
     *
     * @param context
     * @param device
     * @return
     */
    public static UsbDeviceInfo getDeviceInfo(final Context context, final UsbDevice device) {
        return updateDeviceInfo((UsbManager) context.getSystemService(Context.USB_SERVICE), device, new UsbDeviceInfo());
    }

    /**
     * 更新 usb 设备的相关信息
     *
     * @param manager
     * @param device
     * @param _info
     * @return
     */
    public static UsbDeviceInfo updateDeviceInfo(final UsbManager manager, final UsbDevice device, final UsbDeviceInfo _info) {
        //
        final UsbDeviceInfo info = _info != null ? _info : new UsbDeviceInfo();
        info.clear();

        if (device != null) {
            if (BuildCheck.isLollipop()) {
                info.manufacturer = device.getManufacturerName();
                info.product = device.getProductName();
                info.serial = device.getSerialNumber();
            }
            if (BuildCheck.isMarshmallow()) {
                info.usb_version = device.getVersion();
            }

            if ((manager != null) && manager.hasPermission(device)) {

                final UsbDeviceConnection connection = manager.openDevice(device);

                // getRawDescriptors 获取USB设备描述信息
                final byte[] desc = connection.getRawDescriptors();


                if (TextUtils.isEmpty(info.usb_version)) {
                    info.usb_version = String.format("%x.%02x", ((int) desc[3] & 0xff), ((int) desc[2] & 0xff));
                }
                if (TextUtils.isEmpty(info.version)) {
                    info.version = String.format("%x.%02x", ((int) desc[13] & 0xff), ((int) desc[12] & 0xff));
                }
                if (TextUtils.isEmpty(info.serial)) {
                    info.serial = connection.getSerial();
                }

                final byte[] languages = new byte[256];
                int languageCount = 0;
                // controlTransfer(int requestType, int request, int value, int index, byte[] buffer, int length, int timeout)
                try {
                    int result = connection.controlTransfer(
                            USB_REQ_STANDARD_DEVICE_GET, // USB_DIR_IN | USB_TYPE_STANDARD | USB_RECIP_DEVICE
                            USB_REQ_GET_DESCRIPTOR,
                            (USB_DT_STRING << 8) | 0, 0, languages, 256, 0);
                    if (result > 0) {
                        languageCount = (result - 2) / 2;
                    }
                    if (languageCount > 0) {
                        if (TextUtils.isEmpty(info.manufacturer)) {
                            info.manufacturer = getString(connection, desc[14], languageCount, languages);
                        }
                        if (TextUtils.isEmpty(info.product)) {
                            info.product = getString(connection, desc[15], languageCount, languages);
                        }
                        if (TextUtils.isEmpty(info.serial)) {
                            info.serial = getString(connection, desc[16], languageCount, languages);
                        }
                    }
                } finally {
                    connection.close();
                }
            }
            if (TextUtils.isEmpty(info.manufacturer)) {
                info.manufacturer = USBVendorId.vendorName(device.getVendorId());
            }
            if (TextUtils.isEmpty(info.manufacturer)) {
                info.manufacturer = String.format("%04x", device.getVendorId());
            }
            if (TextUtils.isEmpty(info.product)) {
                info.product = String.format("%04x", device.getProductId());
            }
        }
        return info;
    }

    /**
     * 控制类 usb控制模块
     * 当 usb 关闭之后，就不会在使用该实例
     */
    public static final class UsbControlBlock implements Cloneable {

        // 关联弱引用
        private final WeakReference<USBMonitor> mWeakMonitor;

        // UsbDevice：Usb 设备的抽象，它包含一个或多个 UsbInterface
        private final WeakReference<UsbDevice> mWeakDevice;

        // 用于管理连接 host 与 device 建立的连接，并在 endpoint 传输数据
        protected UsbDeviceConnection mConnection;

        // 用于描述 USB 设备信息
        protected final UsbDeviceInfo mInfo;

        // 通信总线编号，设备编号
        private final int mBusNum;
        private final int mDevNum;

        // UsbInterface 定义了设备的功能集，每个 Interface 都是独立的，每个 UsbInterface 包含多个UsbEndpoint
        private final SparseArray<SparseArray<UsbInterface>> mInterfaces = new SparseArray<SparseArray<UsbInterface>>();

        /**
         * 1、这个类在创建之前需要获得访问 USB 的权限
         * 2、打开设备 mUsbManager.openDevice(device);
         * 3、获取总线号、设备号
         *
         * @param monitor
         * @param device
         */
        private UsbControlBlock(final USBMonitor monitor, final UsbDevice device) {
            if (DEBUG) Log.i(TAG, "UsbControlBlock:constructor");

            mWeakMonitor = new WeakReference<USBMonitor>(monitor);
            mWeakDevice = new WeakReference<UsbDevice>(device);

            // 打开 usb 设备，获取连接管理器
            mConnection = monitor.mUsbManager.openDevice(device);

            // 获取传入的 USB 设备的信息
            mInfo = updateDeviceInfo(monitor.mUsbManager, device, null);
            final String name = device.getDeviceName();
            // 如果设备名不为null，就用 "/" 分隔
            final String[] v = !TextUtils.isEmpty(name) ? name.split("/") : null;

            int busnum = 0;
            int devnum = 0;

            if (v != null) {
                // 通过设备名称，去获取总线编号、设备编号
                busnum = Integer.parseInt(v[v.length - 2]);
                devnum = Integer.parseInt(v[v.length - 1]);
            }
            mBusNum = busnum;
            mDevNum = devnum;

//			if (DEBUG) {
            if (mConnection != null) {
                final int desc = mConnection.getFileDescriptor();
                final byte[] rawDesc = mConnection.getRawDescriptors();
                // 打印结果：name=/dev/bus/usb/003/008,desc=52,busnum=3,devnum=8,rawDesc=[B@3330ad97
                Log.i(TAG, String.format(Locale.US, "name=%s,desc=%d,busnum=%d,devnum=%d,rawDesc=", name, desc, busnum, devnum) + rawDesc);
            } else {
                Log.e(TAG, "could not connect to device " + name);
            }
//			}
        }

        /**
         * 用于复制对象的构造器
         * 根据原有对象，获取其监听器、UsbDevice，并打开一个新的连接，重新获取设备的相关信息
         *
         * @param src
         * @throws IllegalStateException
         */
        private UsbControlBlock(final UsbControlBlock src) throws IllegalStateException {
            final USBMonitor monitor = src.getUSBMonitor();
            final UsbDevice device = src.getDevice();

            if (device == null) {
                throw new IllegalStateException("device may already be removed");
            }


            mConnection = monitor.mUsbManager.openDevice(device);

            if (mConnection == null) {
                throw new IllegalStateException("device may already be removed or have no permission");
            }
            mInfo = updateDeviceInfo(monitor.mUsbManager, device, null);
            mWeakMonitor = new WeakReference<USBMonitor>(monitor);
            mWeakDevice = new WeakReference<UsbDevice>(device);
            mBusNum = src.mBusNum;
            mDevNum = src.mDevNum;
            // FIXME USBMonitor.mCtrlBlocksに追加する(今はHashMapなので追加すると置き換わってしまうのでだめ, ListかHashMapにListをぶら下げる?)
        }

        /**
         * 通过clone来复制对象
         * 需要权限
         * USB 监听器从来不会处理克隆出来的 UsbControlBlock，需要在使用以后，手动释放资源
         *
         * @return
         * @throws CloneNotSupportedException
         */
        @Override
        public UsbControlBlock clone() throws CloneNotSupportedException {
            final UsbControlBlock ctrlblock;
            try {
                ctrlblock = new UsbControlBlock(this);
            } catch (final IllegalStateException e) {
                throw new CloneNotSupportedException(e.getMessage());
            }
            return ctrlblock;
        }

        public USBMonitor getUSBMonitor() {
            return mWeakMonitor.get();
        }

        public final UsbDevice getDevice() {
            return mWeakDevice.get();
        }

        /**
         * 获取设备名称
         *
         * @return
         */
        public String getDeviceName() {
            final UsbDevice device = mWeakDevice.get();
            return device != null ? device.getDeviceName() : "";
        }

        /**
         * 获取设备 ID
         *
         * @return
         */
        public int getDeviceId() {
            final UsbDevice device = mWeakDevice.get();
            return device != null ? device.getDeviceId() : 0;
        }

        /**
         * 获取设备的关键字的字符串
         *
         * @return
         */
        public String getDeviceKeyName() {
            return USBMonitor.getDeviceKeyName(mWeakDevice.get());
        }

        /**
         * 获取设备的关键字的字符串
         *
         * @param useNewAPI if true, try to use serial number
         * @return
         * @throws IllegalStateException
         */
        public String getDeviceKeyName(final boolean useNewAPI) throws IllegalStateException {
            if (useNewAPI) {
                checkConnection();
            }
            return USBMonitor.getDeviceKeyName(mWeakDevice.get(), mInfo.serial, useNewAPI);
        }

        /**
         * 获取设备的关键字的字符串
         *
         * @return
         * @throws IllegalStateException
         */
        public int getDeviceKey() throws IllegalStateException {
            checkConnection();
            return USBMonitor.getDeviceKey(mWeakDevice.get());
        }

        /**
         * 获取设备的关键字的字符串
         *
         * @param useNewAPI if true, try to use serial number
         * @return
         * @throws IllegalStateException
         */
        public int getDeviceKey(final boolean useNewAPI) throws IllegalStateException {
            if (useNewAPI) {
                checkConnection();
            }
            return USBMonitor.getDeviceKey(mWeakDevice.get(), mInfo.serial, useNewAPI);
        }

        /**
         * 根据设备的序列号，获取设备的关键字的字符串
         *
         * @return
         */
        public String getDeviceKeyNameWithSerial() {
            return USBMonitor.getDeviceKeyName(mWeakDevice.get(), mInfo.serial, false);
        }

        /**
         * 根据设备的序列号，获取设备的关键字的字符串
         *
         * @return
         */
        public int getDeviceKeyWithSerial() {
            return getDeviceKeyNameWithSerial().hashCode();
        }

        /**
         * 获取连接管理器
         *
         * @return
         */
        public synchronized UsbDeviceConnection getConnection() {
            return mConnection;
        }

        /**
         * 为了访问 USB 设备，需要 getFileDescriptor
         *
         * @return
         * @throws IllegalStateException
         */
        public synchronized int getFileDescriptor() throws IllegalStateException {
            checkConnection();
            return mConnection.getFileDescriptor();
        }

        /**
         * 为了访问 USB 设备，需要 getRawDescriptors
         *
         * @return
         * @throws IllegalStateException
         */
        public synchronized byte[] getRawDescriptors() throws IllegalStateException {
            checkConnection();
            return mConnection.getRawDescriptors();
        }

        /**
         * 获取制造商的 ID
         *
         * @return
         */
        public int getVenderId() {
            final UsbDevice device = mWeakDevice.get();
            return device != null ? device.getVendorId() : 0;
        }

        /**
         * 获取生产商的 ID
         *
         * @return
         */
        public int getProductId() {
            final UsbDevice device = mWeakDevice.get();
            return device != null ? device.getProductId() : 0;
        }

        /**
         * get version string of USB
         *
         * @return
         */
        public String getUsbVersion() {
            return mInfo.usb_version;
        }

        /**
         * get manufacture
         *
         * @return
         */
        public String getManufacture() {
            return mInfo.manufacturer;
        }

        /**
         * get product name
         *
         * @return
         */
        public String getProductName() {
            return mInfo.product;
        }

        /**
         * get version
         *
         * @return
         */
        public String getVersion() {
            return mInfo.version;
        }

        /**
         * get serial number
         *
         * @return
         */
        public String getSerial() {
            return mInfo.serial;
        }

        public int getBusNum() {
            return mBusNum;
        }

        public int getDevNum() {
            return mDevNum;
        }

        /**
         * get interface
         *
         * @param interface_id
         * @throws IllegalStateException
         */
        public synchronized UsbInterface getInterface(final int interface_id) throws IllegalStateException {
            return getInterface(interface_id, 0);
        }

        /**
         * get interface，USB 设备功能集
         *
         * @param interface_id
         * @param altsetting
         * @return
         * @throws IllegalStateException
         */
        public synchronized UsbInterface getInterface(final int interface_id, final int altsetting) throws IllegalStateException {
            checkConnection();

            // mInterfaces，SparseArray集合中装了一个 UsbInterface 的 SparseArray 集合
            // 获取指定 interface_id 的 mInterfaces 集合，内部功能集
            SparseArray<UsbInterface> intfs = mInterfaces.get(interface_id);
            if (intfs == null) {
                // 集合为空，则创建一个 SparseArray 放入 mInterfaces 中
                intfs = new SparseArray<UsbInterface>();
                mInterfaces.put(interface_id, intfs);
            }

            // 获取指定ID为 altsetting 的 UsbInterface,UsbInterface 定义了设备的功能集
            UsbInterface intf = intfs.get(altsetting);

            if (intf == null) {
                final UsbDevice device = mWeakDevice.get();
                // 获取设备的功能数，一个device有很多功能项
                final int n = device.getInterfaceCount();
                // 遍历
                for (int i = 0; i < n; i++) {
                    // 获取具体的功能项
                    final UsbInterface temp = device.getInterface(i);
                    if ((temp.getId() == interface_id) && (temp.getAlternateSetting() == altsetting)) {
                        intf = temp;
                        break;
                    }
                }
                if (intf != null) {
                    intfs.append(altsetting, intf);
                }
            }
            return intf;
        }

        /**
         * open specific interface
         * 打开特定的功能集
         *
         * @param intf
         */
        public synchronized void claimInterface(final UsbInterface intf) {
            claimInterface(intf, true);
        }

        /**
         * 打开特定的功能集,多了一个 force 参数
         *
         * @param intf
         * @param force
         */
        public synchronized void claimInterface(final UsbInterface intf, final boolean force) {
            checkConnection();
            mConnection.claimInterface(intf, force);
        }

        /**
         * 从外部大集合到内部小集合，统统清空，释放 USB 功能集
         *
         * @param intf
         * @throws IllegalStateException
         */
        public synchronized void releaseInterface(final UsbInterface intf) throws IllegalStateException {
            checkConnection();
            // 获取到特定 ID 的功能集
            final SparseArray<UsbInterface> intfs = mInterfaces.get(intf.getId());

            if (intfs != null) {
                final int index = intfs.indexOfValue(intf);
                intfs.removeAt(index);
                if (intfs.size() == 0) {
                    mInterfaces.remove(intf.getId());
                }
            }
            mConnection.releaseInterface(intf);
        }

        /**
         * 关闭设备
         * 依次释放集合内的所有 UsbInterface 资源
         */
        public synchronized void close() {
            if (DEBUG) Log.i(TAG, "UsbControlBlock#close:");

            if (mConnection != null) {
                final int n = mInterfaces.size();
                for (int i = 0; i < n; i++) {
                    final SparseArray<UsbInterface> intfs = mInterfaces.valueAt(i);
                    if (intfs != null) {
                        final int m = intfs.size();
                        for (int j = 0; j < m; j++) {
                            final UsbInterface intf = intfs.valueAt(j);
                            mConnection.releaseInterface(intf);
                        }
                        // 清空内部集合
                        intfs.clear();
                    }
                }
                // 清空外部集合
                mInterfaces.clear();
                // 断开连接
                mConnection.close();
                // 连接器置 null
                mConnection = null;

                final USBMonitor monitor = mWeakMonitor.get();

                if (monitor != null) {
                    if (monitor.mOnDeviceConnectListener != null) {
                        // 调用设备连接监听器的断开连接，连接监听器是暴露在外的接口，供用户操做，内部操做全部有 mConnection 完成
                        // 传入USBDevice、USB控制模块
                        monitor.mOnDeviceConnectListener.onDisconnect(mWeakDevice.get(), UsbControlBlock.this);
                    }
                    // 监听器移除该设备
                    monitor.mCtrlBlocks.remove(getDevice());
                }
            }
        }

        /**
         * 判断对象是否相等，支持两种对象 UsbControlBlock / UsbDevice
         * 其中，mWeakDevice 是 USBDevice 的弱引用，是 UsbControlBlock 的成员变量
         *
         * @param o
         * @return
         */
        @Override
        public boolean equals(final Object o) {
            if (o == null) return false;
            if (o instanceof UsbControlBlock) {
                final UsbDevice device = ((UsbControlBlock) o).getDevice();
                // 根据传入对象是否为null
                // 返回 mWeakDevice 关联的对象的具体是否为 null ，或直接用 equals 对比 UsbControlBlock 关联的 USBDevice
                return device == null ? mWeakDevice.get() == null : device.equals(mWeakDevice.get());
            } else if (o instanceof UsbDevice) {
                return o.equals(mWeakDevice.get());
            }
            return super.equals(o);
        }

//		@Override
//		protected void finalize() throws Throwable {
///			close();
//			super.finalize();
//		}

        // 检测是否是连接状态
        private synchronized void checkConnection() throws IllegalStateException {
            if (mConnection == null) {
                throw new IllegalStateException("already closed");
            }
        }
    }

}
